﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace StockModel
{
	[DebuggerDisplay("Value = {Value}, Date = {Date}")]
	[Serializable]
	public class Quotation : ICloneable
	{
		#region Attributes

		private QuotationData _data;

		#endregion

		#region Properties

		public decimal Value
		{
			get
			{
				return _data.Value;
			}
			set
			{
				_data.Value = value;
			}
		}

		public QuoteType Type
		{
			get
			{
				return _data.Type;
			}
			set
			{
				_data.Type = value;
			}
		}

		public DateTime? _date;
		public DateTime Date
		{
			get
			{
				return _date == null ? DateTime.MinValue : _date.Value;
			}
			set
			{
				if (_acquisition != null && _acquisition.Value.Day != value.Day)
				{
					throw new InvalidOperationException("Tryed to set a quotation date with a day different from the acquisition date");
				}
				_date = value;
			}
		} // 8 byte

		public DateTime? _acquisition;
		public DateTime Acquisition
		{
			get
			{
				return _acquisition == null ? DateTime.MinValue : _acquisition.Value;
			}
			set
			{
				if (_date != null && _date.Value.Day != value.Day)
				{
					throw new InvalidOperationException("Tryed to set a quotation acquisition with a day different from the quotation date");
				}
				_acquisition = value;
			}
		} // 8 byte

		public List<Order> Buyers
		{
			get
			{
				return _data.Buyers;
			}
		}

		public List<Order> Sellers
		{
			get
			{
				return _data.Sellers;
			}
		}

		public int Volume
		{
			get
			{
				return _data.Volume;
			}
			set
			{
				_data.Volume = value;
			}
		}

		#endregion

		#region Public Methods

		public Quotation()
		{
			_data = new QuotationData();
		}

		public override bool Equals(object obj)
		{
			Quotation other = obj as Quotation;

			bool equal = other != null && this.Value == other.Value && this.Volume == other.Volume && this.Type == other.Type;
			equal = equal && this.Buyers.SequenceEqual(other.Buyers) && this.Sellers.SequenceEqual(other.Sellers);

			return equal;
		}

		public override int GetHashCode()
		{
			return string.Format("{0}- {1} - {2}", this.Value, this.Volume, this.Date).GetHashCode();
		}

		public object Clone()
		{
			Quotation result = new Quotation()
			{
				Value = this.Value,
				Acquisition = this.Acquisition,
				Date = this.Date,
				Type = this.Type,
				Volume = this.Volume
			};

			// There will be always the same amount of buyers and sellers
			for (int index = 0; index < this.Buyers.Count; index++)
			{
				result.Buyers.Add((Order)this.Buyers[index].Clone());
				result.Sellers.Add((Order)this.Sellers[index].Clone());
			}

			return result;
		}

		public Quotation ShallowCopy()
		{
			Quotation result = new Quotation();

			result.Acquisition = this.Acquisition;
			result.Date = this.Date;
			result._data = _data;

			return result;
		}

		// Hack to reduce memory footprint to share all the values but the dates on different quotations that share the same values
		private class QuotationData
		{
			#region Attributes

			private decimal _value; // 16 bytes

			#endregion

			#region Properties

			public decimal Value
			{
				get
				{
					return _value;
				}
				set
				{
					_value = Decimal.Parse(value.ToString("####0.####"));
				}
			}

			public QuoteType Type { get; set; } // 1 byte
			public List<Order> Buyers { get; private set; } // 20 * n bytes
			public List<Order> Sellers { get; private set; } // 20 * n bytes
			public int Volume { get; set; } // 4 bytes

			#endregion

			#region Public Methods

			public QuotationData()
			{
				this.Buyers = new List<Order>(1);
				this.Sellers = new List<Order>(1);
			}

			#endregion
		}

		#endregion
	}
}

